using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;

using Athena.Core;

namespace Athena.Objects
{
    [Serializable()]
    public abstract class IGlyph : IDrawable
    {
        public abstract Bitmap GetPreview(int width, int height);

        [CategoryAttribute("IGlyph Attributes"), Description("is this object visible on the menu bar")]        
        public virtual bool HasPreview
        {
            get { return true; }
        }

        protected List<Connector> _IncomingConnections = new List<Connector>(),
                                 _OutgoingConnections = new List<Connector>();

        /// <summary>
        /// Get a list of all the connectors that flow into this glyph
        /// </summary>
        [CategoryAttribute("Connections"), Description("The connections in and out of this node")]
        public virtual List<Connector> IncomingConnections
        {
            get 
            {
                List<Connector> connectors = new List<Connector>();
                foreach (Connector c in _IncomingConnections) connectors.Add(c);
                return connectors; 
            }
        }

        /// <summary>
        /// Get a list of all connectors that flow out of this glyph
        /// </summary>
        [CategoryAttribute("Connections"), Description("The connections in and out of this node")]
        public virtual List<Connector> OutgoingConnections
        {
            get 
            {
                List<Connector> connectors = new List<Connector>();
                foreach (Connector c in _OutgoingConnections) connectors.Add(c);
                return connectors; 
            }
        }

        /// <summary>
        /// adds a new connector. This glyph is an input in that connector. 
        /// @param: connector that has connected to this Glyph
        /// </summary>
        /// <param name="connector"></param>
        public virtual void AddOutgoingConnection(Connector connector)
        {
            if (connector == null) return;
            _OutgoingConnections.Add(connector);
            /*if (ItemPtr != null && ItemPtr is Node)
            {
                ((Node)ItemPtr).AddOutputEdge(connector.ItemPtr as Edge);
            }*/
        }

        /// <summary>
        /// adds a new connector. This glyph is an output in that connector. 
        /// @param: connector that has connected to this Glyph
        /// </summary>
        /// <param name="connector"></param>
        public virtual void AddIncomingConnection(Connector connector)
        {
            if (connector == null) return;
            _IncomingConnections.Add(connector);
            /*if (ItemPtr != null && ItemPtr is Node)
            {
                ((Node)ItemPtr).AddInputEdge(connector.ItemPtr as Edge);
            }*/
        }

        /// <summary>
        /// removes one of the connector that is linked with this glyph
        /// </summary>
        /// <param name="connector"></param>
        public virtual void RemoveConnector(Connector connector)
        {
            if (_IncomingConnections.Contains(connector))
            {
                _IncomingConnections.Remove(connector);
            }
            else
            {
                _OutgoingConnections.Remove(connector);
            }
        }

        /// <summary>
        /// This method is called when the Iglyph is deleted. It allows the Iglyph to remove connected items
        /// </summary>
        public override void Remove()
        {
            Connector e;
            if (_IncomingConnections != null)
                for (int i = _IncomingConnections.Count - 1; i >= 0; --i)
                {
                    if (i >= _IncomingConnections.Count) i = _IncomingConnections.Count - 1;
                    e = _IncomingConnections[i];
                    e.RemoveNode(this);
                    _IncomingConnections.Remove(e);
                }

            if (_OutgoingConnections != null)
                for (int i = _OutgoingConnections.Count - 1; i >= 0; --i)
                {
                    if (i >= _OutgoingConnections.Count) i = _OutgoingConnections.Count - 1;
                    e = _OutgoingConnections[i];
                    e.RemoveNode(this);
                    _OutgoingConnections.Remove(e);
                }

            if (Parent != null)
            {
                Parent = null;
            }

            base.Remove();
        }

        protected float _dEdgeThickness = 2f;
        [CategoryAttribute("IGlyph Attributes"), Description("Thickness of the Edge for the Object.")]
        public float EdgeThickness
        {
            get { return _dEdgeThickness; }
            set { _dEdgeThickness = value; }
        }

        protected Color _oEdgeColor = Color.Black;

        [CategoryAttribute("IGlyph Attributes"), Description("Color of the Object Outline.")]
        public Color EdgeColor
        {
            get { return _oEdgeColor; }
            set { _oEdgeColor = value; }
        }

        protected static Color _oSelectedColor = Color.Red;

        [CategoryAttribute("IGlyph Attributes"), Description("Color of the Object Outline when selected.")]
        public Color SelectedColor
        {
            get { return _oSelectedColor; }
            set { _oSelectedColor = value; }
        }

        protected float _oSelectThickness = 2.0f;

        [CategoryAttribute("IGlyph Attributes"), Description("thickness of the Object Outline when selected.")]
        public float SelectedThickness
        {
            get { return _oSelectThickness; }
            set { _oSelectThickness = value; }
        }

        public override void Transform(System.Drawing.PointF oDirection, ref Corner oCorner, bool Ctrl)
        {
            if (Ctrl)
            {
                _Dimensions.Width = _Dimensions.Height = (_Dimensions.Width + _Dimensions.Height) / 2f;
                float avg = (Math.Abs(oDirection.X) + Math.Abs(oDirection.Y))/2f;
                if (oDirection.X > 0 && oDirection.Y > 0)
                    oDirection = new PointF(avg, avg);
                else
                {
                    if (oDirection.X < 0 && oDirection.Y < 0)
                        oDirection = new PointF(-avg, -avg);
                    else
                    {
                        if (oDirection.X < 0)
                            oDirection = new PointF(-avg, avg);
                        else
                            oDirection = new PointF(avg, -avg);
                    }
                }
            }
            switch (oCorner)
            {
                case Corner.BottomLeft:
                    {
                        foreach (IDrawable id in AnchoredItems)
                        {
                            if (id.Location.X < Bounds.Left && id.Location.Y > Bounds.Bottom)
                                id.Translate(oDirection);
                            else
                            {
                                if (id.Location.X < Bounds.Left)
                                    id.Translate(new PointF(oDirection.X, 0));
                                if (id.Location.Y > Bounds.Bottom)
                                    id.Translate(new PointF(0, oDirection.Y));
                            }
                        }

                        _Location.X += oDirection.X;
                        _Dimensions.Width -= oDirection.X;

                        if (_oLabelBounds.Y > _Dimensions.Height / 2)
                        {
                            _oLabelBounds.Y += oDirection.Y;
                        }

                        _Dimensions.Height += oDirection.Y;
                        break;
                    }
                case Corner.BottomRight:
                    {
                        foreach (IDrawable id in AnchoredItems)
                        {
                            if (id.Location.X >= Bounds.Right && id.Location.Y >= Bounds.Bottom)
                                id.Translate(oDirection);
                            else
                            {
                                if (id.Location.X >= Bounds.Right)
                                    id.Translate(new PointF(oDirection.X,0));
                                if (id.Location.Y >= Bounds.Bottom)
                                    id.Translate(new PointF(0,oDirection.Y));
                            }
                        }
                        if (_oLabelBounds.X > _Dimensions.Width / 2)
                        {
                            _oLabelBounds.X += oDirection.X;
                        }
                        if (_oLabelBounds.Y > _Dimensions.Height / 2)
                        {
                            _oLabelBounds.Y += oDirection.Y;
                        }
                        _Dimensions.Width += oDirection.X;
                        _Dimensions.Height += oDirection.Y;
                        break;
                    }
                case Corner.TopLeft:
                    {
                        foreach (IDrawable id in AnchoredItems)
                        {
                            if (id.Location.X <= Bounds.Left && id.Location.Y >= Bounds.Top)
                                id.Translate(oDirection);
                            else
                            {
                                if (id.Location.X <= Bounds.Left)
                                    id.Translate(new PointF(oDirection.X, 0));
                                if (id.Location.Y >= Bounds.Top)
                                    id.Translate(new PointF(0, oDirection.Y));
                            }
                        }
                        _Location.X += oDirection.X;
                        _Location.Y += oDirection.Y;
                        _Dimensions.Width -= oDirection.X;
                        _Dimensions.Height -= oDirection.Y;
                        break;
                    }
                case Corner.TopRight:
                    {
                        foreach (IDrawable id in AnchoredItems)
                        {
                            if (id.Location.X >= Bounds.Right && id.Location.Y >= Bounds.Top)
                                id.Translate(oDirection);
                            else
                            {
                                if (id.Location.X >= Bounds.Right)
                                    id.Translate(new PointF(oDirection.X, 0));
                                if (id.Location.Y >= Bounds.Top)
                                    id.Translate(new PointF(0, oDirection.Y));
                            }
                        }
                        if (_oLabelBounds.X > _Dimensions.Width / 2)
                        {
                            _oLabelBounds.X += oDirection.X;
                        }
                        _Location.Y += oDirection.Y;
                        _Dimensions.Width += oDirection.X;
                        _Dimensions.Height -= oDirection.Y;
                        break;
                    }

                default:
                    break;
            }

            if (_Dimensions.Height < 0)
            {
                _Dimensions.Height = 0;
                oCorner = FlipCornerY(oCorner);
            }
            if (_Dimensions.Width < 0)
            {
                _Dimensions.Width = 0;
                oCorner = FlipCornerX(oCorner);
            }

        }
        public Corner FlipCornerY(Corner oCorner)
        {
            switch (oCorner)
            {
                case Corner.BottomLeft:
                    return Corner.TopLeft;
                case Corner.BottomRight:
                    return Corner.TopRight;
                case Corner.TopLeft:
                    return Corner.BottomLeft;
                case Corner.TopRight:
                    return Corner.BottomRight;
                default:
                    return Corner.None;
            }
        }
        public Corner FlipCornerX(Corner oCorner)
        {
            switch (oCorner)
            {
                case Corner.BottomLeft:
                    return Corner.BottomRight;
                case Corner.BottomRight:
                    return Corner.BottomLeft;
                case Corner.TopLeft:
                    return Corner.TopRight;
                case Corner.TopRight:
                    return Corner.TopLeft;
                default:
                    return Corner.None;
            }
        }
        public override Corner Where(RectangleF oRect)
        {
            RectangleF oBounds = Bounds;
            oBounds.Inflate(5, 5);
            RectangleF oTopLeft = new RectangleF(oBounds.Left - 3F, oBounds.Top - 3F, 6F, 6F);
            RectangleF oTopRight = new RectangleF(oBounds.Right - 3F, oBounds.Top - 3F, 6F, 6F);
            RectangleF oBottomLeft = new RectangleF(oBounds.Left - 3F, oBounds.Bottom - 3F, 6F, 6F);
            RectangleF oBottomRight = new RectangleF(oBounds.Right - 3F, oBounds.Bottom - 3F, 6F, 6F);

            if (oTopLeft.IntersectsWith(oRect)) return Corner.TopLeft;
            if (oTopRight.IntersectsWith(oRect)) return Corner.TopRight;
            if (oBottomLeft.IntersectsWith(oRect)) return Corner.BottomLeft;
            if (oBottomRight.IntersectsWith(oRect)) return Corner.BottomRight;

            return Corner.None;
        }
        public override Corner Where(PointF oPoint)
        {
            RectangleF oBounds = Bounds;
            oBounds.Inflate(5, 5);
            RectangleF oTopLeft = new RectangleF(oBounds.Left - 5F, oBounds.Top - 5F, 10F, 10F);
            
            RectangleF oTopRight = new RectangleF(oBounds.Right - 5F, oBounds.Top - 5F, 10F, 10F);
            
            RectangleF oBottomLeft = new RectangleF(oBounds.Left - 5F, oBounds.Bottom - 5F, 10F, 10F);
            
            RectangleF oBottomRight = new RectangleF(oBounds.Right - 5F, oBounds.Bottom - 5F, 10F, 10F);
            

            if (oTopLeft.Contains(oPoint)) return Corner.TopLeft;
            if (oTopRight.Contains(oPoint)) return Corner.TopRight;
            if (oBottomLeft.Contains(oPoint)) return Corner.BottomLeft;
            if (oBottomRight.Contains(oPoint)) return Corner.BottomRight;
            return Corner.None;
        }


        protected bool _IsSelected;
        public override bool IsSelected
        {
            get
            {
                return _IsSelected;
            }
            set
            {
                _IsSelected = value;
            }
        }
        public override void Select() 
        { 
            _IsSelected = true;
        }
        public override void Deselect() { _IsSelected = false; }


        protected PointF _Location = new PointF(),
                         _OldLocation = new PointF();
        public override PointF Location
        {
            get
            {
                return _Location;
            }
            set
            {   
                _Location = value;
            }
        }

        protected SizeF _Dimensions;
        public override SizeF Dimensions
        {
            get
            {
                return _Dimensions;
            }
            set
            {
                if (_oLabelBounds.X > _Dimensions.Width / 2)
                {
                    _oLabelBounds.X += (value.Width - _Dimensions.Width);
                }
                if (_oLabelBounds.Y > _Dimensions.Height / 2)
                {
                    _oLabelBounds.Y += (value.Height - _Dimensions.Height);
                }
                _Dimensions = value;
            }
        }

        public override RectangleF Bounds
        {
            get
            {
                return new RectangleF(_Location, _Dimensions);
            }
            set
            {
                _Location = value.Location;
                _Dimensions = value.Size;
            }
        }

        /// <summary>
        /// Render the Glyph into the given graphics context, so that, at the end it fits 
        /// into the Bounds, as given by the properties.
        /// </summary>
        /// <param name="g">the graphics context</param>
        public abstract void RenderGlyph(Graphics g);

        protected RectangleF _oLabelBounds = new RectangleF();
        protected bool _bLabelBoundsChanged = false;
        [System.ComponentModel.CategoryAttribute("IGlyph Attributes"),
        System.ComponentModel.DescriptionAttribute("Bounds of the Label, Position is relative to the position of the glyph."),
    ReadOnlyAttribute(false), TypeConverter(typeof(RectangleFConverter))]
        public RectangleF LabelBounds
        {
            get { return _oLabelBounds; }
            set { 
                _bLabelBoundsChanged = true;
                _oLabelBounds = value;

                //_oLabelBounds.Location = Utility.SubtractPoints(_oLabelBounds.Location, Bounds.Location);
            }
        }


        public void AddLabelGlyph(SBMLExtension.EmlRenderExtension.RenderInformation oInfo, SBMLExtension.EmlRenderExtension.Group oGroup)
        {
            if (!string.IsNullOrEmpty(Text) && ShowText)
            {
                SBMLExtension.EmlRenderExtension.Text oText = new SBMLExtension.EmlRenderExtension.Text();
                oText.FontFamily = TextFont.FontFamily.Name;
                oText.FontSize = TextFont.SizeInPoints.ToString();
                oText.Stroke = oInfo.AddColorDefinition(TextColor);
                if (TextFont.Bold) oText.FontWeight = SBMLExtension.EmlRenderExtension.Text.FontWeiths.bold.ToString();
                if (TextFont.Italic) oText.FontStyle = SBMLExtension.EmlRenderExtension.Text.FontStyles.italic.ToString();
                oText.StrokeWidth = "1";
                
                float fLabelLength = (TextFont.SizeInPoints * 0.7f * Text.Length);
                switch (TextH)
                {
                    case HorizontalAlignment.Center:
                        oText.X = "50%";
                        oText.TextAnchor = "middle";
                            // (Bounds.Width / 2f - fLabelLength/2f).ToString();
                        break;
                    case HorizontalAlignment.Left:
                        //oText.X = (1f).ToString();
                        oText.TextAnchor = "start";
                        oText.X = "1%";
                        break;
                    case HorizontalAlignment.Right:
                        //oText.X = (Bounds.Width - fLabelLength).ToString();
                        oText.TextAnchor = "end";
                        oText.X = "99%";
                        break;
                    case HorizontalAlignment.LeftOfLeft:
                        //oText.X = (-fLabelLength - 10f).ToString();
                        oText.TextAnchor = "start";
                        oText.X = "-10%";
                        break;
                    case HorizontalAlignment.RightOfRight:
                        //oText.X = (Bounds.Width +10f).ToString();
                        oText.TextAnchor = "start";
                        oText.X = "110%";
                        break;
                    default:
                    case HorizontalAlignment.None:
                        oText.TextAnchor = "middle";
                        oText.X = "50%";
                        break;
                }
                float fLabelHeight = TextFont.Height * 1f;
                switch (TextV)
                {

                    case VerticalAlignment.Middle:
                        oText.Y = "50%";
                        //oText.Y = (Bounds.Height / 2f - fLabelHeight/3f).ToString();
                        break;
                    case VerticalAlignment.Top:
                        oText.Y = "0%";
                        //oText.Y = (fLabelHeight).ToString();
                        break;                    
                    case VerticalAlignment.Bottom:
                        oText.Y = "100%";
                        //oText.Y = (Bounds.Height - fLabelHeight).ToString();
                        break;
                    case VerticalAlignment.AboveTop:
                        oText.Y = "-20%";
                        //oText.Y = ( - 2 * fLabelHeight).ToString();
                        break;
                    case VerticalAlignment.BelowBottom:
                        oText.Y = "120%";
                        //oText.Y = (Bounds.Height + 2 * fLabelHeight).ToString();
                        break;
                    case VerticalAlignment.None:
                    default:
                        oText.Y = "50%";                        
                        break;
                }                               
                
                oText.TheText = Text;
                oGroup.Children.Add(oText);
            }
        }


        public virtual void DrawLabel(Graphics g)
        {
            if (_oLabelFont == null)
            {
                return;
            }
            if (Dimensions.Height > 0)
            {



                RectangleF oLabelBounds = Bounds;
                Font oLabelFont = null;
                //if (_bLabelChanged)
                //{
                oLabelFont = _oLabelFont;
                /*}
                else
                {
                    oLabelFont = new Font(
                        _oLabelFont.FontFamily,
                        oLabelBounds.Height / 4f,
                        _oLabelFont.Style,
                        _oLabelFont.Unit,
                        _oLabelFont.GdiCharSet,
                        _oLabelFont.GdiVerticalFont);
                }*/
                
                SizeF oSize = g.MeasureString(Text, oLabelFont,int.MaxValue );

                if (oSize.Width > Bounds.Width && TextH != HorizontalAlignment.LeftOfLeft && TextH != HorizontalAlignment.RightOfRight)
                {
                    TextV = VerticalAlignment.BelowBottom;
                    //oLabelBounds.Width += oSize.Width + oSize.Width / 10f;
                }

                //if (oSize.Height > Bounds.Height && LabelV != VerticalAlignment.AboveTop && LabelV != VerticalAlignment.BelowBottom)
                //    LabelV = VerticalAlignment.BelowBottom;

                switch (TextH)
                {                                           
                    case HorizontalAlignment.LeftOfLeft:
                        oLabelBounds.X = oLabelBounds.X - oSize.Width - oSize.Width / 10f;
                        oLabelBounds.Width += oSize.Width + oSize.Width / 10f;
                        break;
                    case HorizontalAlignment.RightOfRight:
                        oLabelBounds.X = oLabelBounds.X + oLabelBounds.Width +  oSize.Width / 10f;
                        oLabelBounds.Width += oSize.Width + oSize.Width / 10f;
                        break;
                    case HorizontalAlignment.Left:
                        oLabelBounds.X = oLabelBounds.X;
                        break;
                    case HorizontalAlignment.Center:
                        oLabelBounds.X = oLabelBounds.X + oLabelBounds.Width / 2f - oSize.Width / 2f;
                        break;
                    case HorizontalAlignment.Right:
                        oLabelBounds.X = oLabelBounds.X + oLabelBounds.Width - oSize.Width;
                        break;
                    default:
                    case HorizontalAlignment.None:
                        {
                            if (_bLabelBoundsChanged)
                            {
                                oLabelBounds = _oLabelBounds;
                                oLabelBounds.Location = Utility.AddPoints(_oLabelBounds.Location, Bounds.Location);
                            }
                            else
                            {

                                oLabelBounds.Width = Bounds.Width;
                                oLabelBounds.Height = Bounds.Height / 2f;
                            }
                            break;
                        }
                }





                switch (TextV)
                {
                                        
                    case VerticalAlignment.AboveTop:
                        oLabelBounds.Y = oLabelBounds.Y - oSize.Height - oSize.Height * 0.1f ;
                        oLabelBounds.Height += oSize.Height + oSize.Height * 0.1f;
                        oLabelBounds.Width += oSize.Width + oSize.Width / 10f;
                        break;
                    case VerticalAlignment.BelowBottom:
                        oLabelBounds.Y = oLabelBounds.Y  + oLabelBounds.Height + oSize.Height * 0.1f;
                        oLabelBounds.Width += oSize.Width + oSize.Width / 10f;
                        oLabelBounds.Height += oSize.Height + oSize.Height * 0.1f;
                        break;
                    case VerticalAlignment.Top:
                        oLabelBounds.Y = oLabelBounds.Y;
                        break;
                    case VerticalAlignment.Middle:
                        oLabelBounds.Y = oLabelBounds.Y + oLabelBounds.Height /2f - oSize.Height /2f;
                        break;
                    case VerticalAlignment.Bottom:
                        oLabelBounds.Y = oLabelBounds.Y + oLabelBounds.Height - oSize.Height;
                        break;
                    default:
                    case VerticalAlignment.None:
                        break;
                }



                

                if (!_bLabelBoundsChanged && TextV == VerticalAlignment.None && TextH == HorizontalAlignment.None)
                {
                    oLabelBounds.X += (oLabelBounds.Width - oSize.Width) / 2f;
                    oLabelBounds.Y += oSize.Height / 8f;
                    //oLabelBounds.Y += (oLabelBounds.Height - oSize.Height) / 2f;
                    oLabelBounds.Width = oSize.Width;
                    oLabelBounds.Height = oSize.Height;
                }

                g.DrawString(Text, oLabelFont, new SolidBrush(_oLabelColor), oLabelBounds);
            }

        }

        protected int _nMultiplicity = 1;
        [CategoryAttribute("IGlyph Attributes"), Description("mulimer number")]        
        public int Multiplicity
        {
            get { return _nMultiplicity; }
            set { _nMultiplicity = value; }
        }
        public override void DoneModifying(Corner oCorner, bool modifyAnchoredItems)
        {
            _OldLocation = _Location;
            base.DoneModifying(oCorner, modifyAnchoredItems);
            foreach (Connector c in _IncomingConnections)
                c.DoneModifying(oCorner,false);
            foreach (Connector c in _OutgoingConnections)
                c.DoneModifying(oCorner,false);
        }
        public override void UndoMove()
        {
            MoveTo(_OldLocation);
        }
        public override void Draw(Graphics g)
        {
            if (IsVisible)
            {
                if (_nMultiplicity > 1)
                {
                    _Location.X += 4f;
                    _Location.Y += 4f;
                    RenderGlyph(g);
                    _Location.X -= 4f;
                    _Location.Y -= 4f;
                }
                if (_Original != null && !(Item is GlobalSpecies))
                {
                    PointF p1 = new PointF(_Location.X + _Dimensions.Width + 1, _Location.Y - 1),
                           p2 = new PointF(p1.X + 6,p1.Y - 6);
                    g.DrawLine(new Pen(Color.Red, 3), p1, p2);
                }
                RenderGlyph(g);
            }

            if (ShowText)
                DrawLabel(g);

            if (_IsSelected)
            {
                Pen pen = new Pen(_oSelectedColor, _oSelectThickness);
                RectangleF oBounds = Bounds;

                //Color oColor = Color.FromArgb(128, Color.LightBlue);
                //SolidBrush oBrush = new SolidBrush(oColor);

                //g.FillRectangle(oBrush, oBounds);

                oBounds.Inflate(2.5F, 2.5F);

                //g.DrawRectangle(Pens.Red, oBounds.Location.X, oBounds.Location.Y, oBounds.Size.Width, oBounds.Size.Height);

                g.DrawLine(pen, oBounds.Location.X + 3, oBounds.Location.Y, oBounds.Location.X + oBounds.Size.Width - 3, oBounds.Location.Y);
                g.DrawLine(pen, oBounds.Location.X + 3, oBounds.Location.Y + oBounds.Height, oBounds.Location.X + oBounds.Width - 3, oBounds.Location.Y + oBounds.Height);
                g.DrawLine(pen, oBounds.Location.X, oBounds.Location.Y + 3, oBounds.Location.X, oBounds.Location.Y + oBounds.Height - 3);
                g.DrawLine(pen, oBounds.Location.X + oBounds.Width, oBounds.Location.Y + 3, oBounds.Location.X + oBounds.Width, oBounds.Location.Y + oBounds.Height - 3);


                //g.FillEllipse(Brushes.White, oBounds.Left - 3, oBounds.Top - 3, 6, 6);
                g.DrawEllipse(pen, oBounds.Left - 3, oBounds.Top - 3, 6, 6);

                //g.FillEllipse(Brushes.White, oBounds.Right - 3, oBounds.Top - 3, 6, 6);
                g.DrawEllipse(pen, oBounds.Right - 3, oBounds.Top - 3, 6, 6);

                //g.FillEllipse(Brushes.White, oBounds.Left - 3, oBounds.Bottom - 3, 6, 6);
                g.DrawEllipse(pen, oBounds.Left - 3, oBounds.Bottom - 3, 6, 6);

                //g.FillEllipse(Brushes.White, oBounds.Right - 3, oBounds.Bottom - 3, 6, 6);
                g.DrawEllipse(pen, oBounds.Right - 3, oBounds.Bottom - 3, 6, 6);


                //oBrush.Dispose();
            }

        }

        /// <summary>
        /// writes the iglyph attributes to xml
        /// </summary>
        /// <param name="writer"></param>
        public override void WriteXML(System.Xml.XmlWriter writer)
        {
            base.WriteXML(writer);

            writer.WriteStartElement("IGlyph", "");

            writer.WriteStartElement("EdgeThickness");
            writer.WriteValue(_dEdgeThickness);
            writer.WriteEndElement();

            writer.WriteStartElement("Multiplicity");
            writer.WriteValue(_nMultiplicity);
            writer.WriteEndElement();

            writer.WriteStartElement("EdgeColor");
            writer.WriteValue(_oEdgeColor.Name);
            writer.WriteEndElement();

            writer.WriteStartElement("LabelWidth");            
            writer.WriteValue(_oLabelBounds.Width);
            writer.WriteEndElement();

            writer.WriteStartElement("LabelHeight");
            writer.WriteValue(_oLabelBounds.Height);
            writer.WriteEndElement();

            writer.WriteStartElement("SelectedColor");
            writer.WriteValue(_oSelectedColor.Name);
            writer.WriteEndElement();

            writer.WriteStartElement("SelectedThickness");
            writer.WriteValue(_oSelectThickness);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
        /// <summary>
        /// reads the iglyph attributes from xml
        /// </summary>
        /// <param name="writer"></param>
        public override bool ReadXML(XmlReader reader)
        {
            bool read = base.ReadXML(reader);
            read = reader.Read();
            
            if (reader.NodeType == XmlNodeType.Element && reader.Name == "IGlyph")
            {
                read = reader.Read();
                while (read)
                {
                    if (reader.NodeType == XmlNodeType.EndElement)
                        break;

                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        switch (reader.Name)
                        {
                            case "EdgeThickness":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                    _dEdgeThickness = reader.ReadContentAsFloat();
                                
                                break;
                            case "Multiplicity":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                    _nMultiplicity = reader.ReadContentAsInt();
                                
                                break;
                            case "EdgeColor":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                    _oEdgeColor = Color.FromName(reader.ReadContentAsString());
                                
                                break;
                            case "LabelWidth":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                {
                                    _oLabelBounds = new RectangleF(_oLabelBounds.X,_oLabelBounds.Y,
                                                                   reader.ReadContentAsFloat(), _oLabelBounds.Height);
                                }
                                
                                break;
                            case "LabelHeight":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                {
                                    _oLabelBounds = new RectangleF(_oLabelBounds.X, _oLabelBounds.Y,
                                                                   _oLabelBounds.Width, reader.ReadContentAsFloat());
                                }
                                
                                break;
                            case "SelectedThickness":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                    _oSelectThickness = reader.ReadContentAsFloat();
                                
                                break;
                            case "SelectedColor":
                                read = reader.Read();
                                if (reader.NodeType == XmlNodeType.Text)
                                    _oSelectedColor = Color.FromName(reader.ReadContentAsString());
                                
                                break;
                            default:
                                while (reader.NodeType != XmlNodeType.EndElement)
                                    read = reader.Read();
                                break;
                        }
                    }

                    if (!read || (reader.NodeType == XmlNodeType.EndElement && reader.Name == "IGlyph")) break;

                    if (reader.NodeType != XmlNodeType.Element)
                        read = reader.Read();
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// An optional function for loading the defaults of this drawable, if one exists
        /// </summary>
        public override void LoadDefaults(IDrawable drawable)
        {
            IGlyph Default = drawable as IGlyph;
            if (Default != null)
            {
                ColorEnd = Default.ColorEnd;
                ColorStart = Default.ColorStart;
                SelectedColor = Default.SelectedColor;
                EdgeColor = Default.EdgeColor;
                EdgeThickness = Default.EdgeThickness;
                ShowText = Default.ShowText;
                TextColor = Default.TextColor;
                View = Default.View;
                Dimensions = Default.Dimensions;                
                LabelBounds = Default.LabelBounds;
                SelectedThickness = Default.SelectedThickness;
                TextH = Default.TextH;
                TextV = Default.TextV;
            }
        }


        private bool _ShowCloneMarker = false;
        public bool ShowCloneMarker
        {
            get { return _ShowCloneMarker; }
            set { _ShowCloneMarker = value; }
        }


        public Color CloneMarkerColor
        {
            get
            {
                return _CloneMarkerColor;
            }
            set
            {
                _CloneMarkerColor = value;
            }
        }
        private static Color _CloneMarkerColor = Color.Orange;
        private static float _ClonePercentage = 0.25f;
        public float ClonePercentage
        {
            get
            {
                return _ClonePercentage;
            }
            set
            {
                _ClonePercentage = value;
            }
        }

        private string _CloneMarkerText = "";
        public string CloneMarkerText
        {
            get { return _CloneMarkerText; }
            set { _CloneMarkerText = value; }
        }

        private Color _CloneMarkerTextColor = Color.White;
        public Color CloneMarkerTextColor
        {
            get { return _CloneMarkerTextColor; }
            set { _CloneMarkerTextColor = value; }
        }

        private Font _CloneMarkerTextFont = SystemFonts.DefaultFont;
        public Font CloneMarkerTextFont
        {
            get { return _CloneMarkerTextFont; }
            set { _CloneMarkerTextFont = value; }
        }

        protected void AddCloneMarkerGradient(SBMLExtension.EmlRenderExtension.RenderInformation oInfo)
        {
            bool bFound = false;
            foreach (SBMLExtension.EmlRenderExtension.GradientDefinition def in oInfo.GradientDefinitions)
            {
                if (def.ID == "cloneMarker") { bFound = true; break; }
            }
            if (!bFound)
            {
                SBMLExtension.EmlRenderExtension.LinearGradient def = new SBMLExtension.EmlRenderExtension.LinearGradient();
                def.ID = "cloneMarker"; def.SpreadMethod = "pad";
                def.X1 = "50%"; def.Y1 = "0%"; def.X2 = "50%"; def.Y2 = "100%";
                def.Stop.Add(new SBMLExtension.EmlRenderExtension.GradientStop("0.0", Color.Transparent));
                def.Stop.Add(new SBMLExtension.EmlRenderExtension.GradientStop((1f - ClonePercentage).ToString(), Color.Transparent));
                def.Stop.Add(new SBMLExtension.EmlRenderExtension.GradientStop((1f - ClonePercentage).ToString(), CloneMarkerColor));
                def.Stop.Add(new SBMLExtension.EmlRenderExtension.GradientStop("1.0", CloneMarkerColor));
                oInfo.GradientDefinitions.Add(def);
            }
        }

        public void AddCloneMarkerText(SBMLExtension.EmlRenderExtension.RenderInformation oInfo, SBMLExtension.EmlRenderExtension.Group oGroup)
        {
            if (!string.IsNullOrEmpty(CloneMarkerText) && ShowCloneMarker)
            {
                if (_CloneMarkerTextFont == null) _CloneMarkerTextFont = SystemFonts.DefaultFont;
                if (_CloneMarkerTextColor == Color.Empty) _CloneMarkerTextColor = Color.White;

                SBMLExtension.EmlRenderExtension.Text oText = new SBMLExtension.EmlRenderExtension.Text();
                oText.FontFamily = _CloneMarkerTextFont.FontFamily.Name;
                oText.FontSize = _CloneMarkerTextFont.SizeInPoints.ToString();
                oText.Stroke = oInfo.AddColorDefinition(_CloneMarkerTextColor);
                if (_CloneMarkerTextFont.Bold) oText.FontWeight = SBMLExtension.EmlRenderExtension.Text.FontWeiths.bold.ToString();
                if (_CloneMarkerTextFont.Italic) oText.FontStyle = SBMLExtension.EmlRenderExtension.Text.FontStyles.italic.ToString();
                oText.StrokeWidth = "1";
                oText.TextAnchor = "middle"; oText.X = "50%"; oText.Y = ((1- ClonePercentage / 2f)*100f).ToString() + "%";
                float fLabelLength = (_CloneMarkerTextFont.SizeInPoints * 0.7f * Text.Length);

                oText.TheText = CloneMarkerText;
                oGroup.Children.Add(oText);

            }
        }


        public void DrawCloneMarkerText(Graphics g)
        {
            if (string.IsNullOrEmpty(CloneMarkerText) || !ShowCloneMarker) return;
            if (_CloneMarkerTextFont == null) _CloneMarkerTextFont = SystemFonts.DefaultFont;
            if (_CloneMarkerTextColor == Color.Empty) _CloneMarkerTextColor = Color.White;
            SizeF size = g.MeasureString(CloneMarkerText, CloneMarkerTextFont);

            PointF point = new PointF(
                Bounds.X + Bounds.Width / 2f - size.Width/2f, 
                Bounds.Y + Bounds.Height * (1f - ClonePercentage/2f) - size.Height/2f
                );

            g.DrawString(CloneMarkerText, CloneMarkerTextFont, new SolidBrush(CloneMarkerTextColor), point);
        }


    }
}
